package com.lagou.edu.annotation;


import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.utils.ComponentScanUtil;

import java.io.File;
import java.io.FileFilter;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author <p>
 * 工厂类，通过扫描注解生产对象
 */
public class AnnotationApplicationContext {
    private Map<String, Object> beanMap = new HashMap<>();

    private Map<String, Object> serviceMap = new HashMap<String, Object>();

    private Map<String, Object> transactionMap = new HashMap<String, Object>();


    private Map<String, Object> autoWiredMap = new HashMap<String, Object>();

    public AnnotationApplicationContext(String pkgName) {
        scanPackage(pkgName);
        creatAutoWiredBean();
        creatTransactionBean();
    }

    public AnnotationApplicationContext() {

    }

    private void scanPackage(String pkg) {
        List<String> sacnBeanList = ComponentScanUtil.getInstance().getSacnBean(pkg);
        for (String f : sacnBeanList) {
            String beanName = f.substring(f.lastIndexOf(".") + 1);
            //将名字的第一个字母转为小写(用它作为key存储map)
            String key = String.valueOf(beanName.charAt(0)).toLowerCase() + beanName.substring(1);
            try {
                //反射构建对象
                Class<?> c = Class.forName(f);

                Object obj = null;
                //判定类上是否有注解isAnnotationPresent()
                if (c.isAnnotationPresent(Service.class)
                ) {
                    //如果有定义了名称，采用定义的
                    Service service = c.getAnnotation(Service.class);
                    String value = service.value();
                    if (!(value.equals(""))) {
                        key = value;
                    }
                    obj = c.newInstance();
                    serviceMap.put(key, obj);
                    beanMap.put(key, obj);
                }
                if (c.isAnnotationPresent(Transactional.class)
                ) {
                    Transactional transactional = c.getAnnotation(Transactional.class);
                    String value = transactional.value();
                    if (!(value.equals(""))) {
                        key = value;
                    }
                    obj = c.newInstance();
                    transactionMap.put(key, obj);
                    beanMap.put(key, obj);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //处理AutoWired注解
    private void creatAutoWiredBean() {

        for (String key : beanMap.keySet()) {
            try {
                Object bean = beanMap.get(key);
                Class<?> c = bean.getClass();
                Field[] declaredFields = c.getDeclaredFields();
                for (Field field : declaredFields) {
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    if (autowired != null) {
                        //反射时访问私有变量
                        field.setAccessible(true);
                        field.set(bean, getBean(field.getName()));
                    }
                }
                beanMap.put(key, bean);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
    }
   //处理Transaction注解
    private void creatTransactionBean() {
        ProxyFactory proxyFactory =(ProxyFactory) beanMap.get("proxyFactory");
        for (String key : transactionMap.keySet()) {
            try {
                Object bean = beanMap.get(key);
                Object proxy = null;
                Class<?>[] interfaces = bean.getClass().getInterfaces();
                if(interfaces==null){
                    proxy=proxyFactory.getCglibProxy(bean);
                }else{
                    proxy=proxyFactory.getJdkProxy(bean);
                }
                beanMap.put(key, proxy);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }


    public Object getBean(String key) {
        return beanMap.get(key);
    }

    public void close() {
        beanMap.clear();
        beanMap = null;
    }
}











































































